using System;

namespace ValidationFramework.Specifications
{
    /// <summary>
    /// Performs a required field validation on a <see cref="string"/>.
    /// </summary>
    /// <seealso cref="RequiredStringRuleConfigReader"/>
	/// <seealso cref="RequiredStringRuleAttribute"/>
#if (!SILVERLIGHT)
    [Serializable]
#endif
    public class IsRequiredStringSpec : IsRequiredSpec<string>
	{
        // --- Fields

        private StringComparison? stringComparison;


        // --- Constructors
        
        /// <param name="initialValue">The initial and invalid value.</param>
        /// <param name="trimWhiteSpace">A <see cref="bool"/> to indicate if whitespace should be trimmed from <paramref name="initialValue"/> and the value being validated.</param>
        /// <param name="ignoreCase">A <see cref="bool"/> to indicate if case should be ignored.</param>
		/// <exception cref="NullReferenceException"><paramref name="initialValue"/> is null.</exception>
        /// <exception cref="ArgumentException"><paramref name="errorMessage"/> is a <see cref="string.Empty"/>.</exception>
        public IsRequiredStringSpec(string initialValue, bool trimWhiteSpace, bool? ignoreCase)
        {
			this.InitialValue = initialValue;
            TrimWhiteSpace = trimWhiteSpace;
            IgnoreCase = ignoreCase;
			if (IgnoreCase == true)
            {
                stringComparison = StringComparison.OrdinalIgnoreCase;
            }
            else
            {
                stringComparison = StringComparison.Ordinal;
            }
        }


        // --- Properties

        /// <summary>
        /// Gets a <see cref="bool"/> to indicate if whitespace should be trimmed from the value being validated.
        /// </summary>
        public bool TrimWhiteSpace
        {
			get;
			private set;
        }

        /// <summary>
        /// Gets a <see cref="bool"/> to indicate if case should be ignored.
        /// </summary>
        public bool? IgnoreCase
        {
            get; 
			private set;
        }


        // --- Methods

		/// <inheritdoc />
		public override string ToString()
		{
			if (HasInitialValue)
			{
				return string.Format("The value must not be {0}", InitialValue);
			}
			else
			{
				if (TrimWhiteSpace)
				{
					return string.Format("The value must not be null or an empty string. All spaces are ignored.");
				}
				else
				{
					return string.Format("The value must not be null or an empty string.");
				}
			}
		}

		/// <inheritdoc />
		public override bool IsEquivalentTo(ISpecification specification)
		{
			var rsSpecification = (IsRequiredStringSpec)specification;
            return base.IsEquivalentTo(rsSpecification) 
				&& rsSpecification.TrimWhiteSpace == TrimWhiteSpace 
				&& rsSpecification.IgnoreCase == IgnoreCase;
		}

		/// <inheritdoc />
		public override bool IsSatisfiedBy(object target)
		{
			//Since String can be null or empty, need to do an explicit check
			//Always check for null before casting.
			if (HasInitialValue)
			{
				if (target == null)
				{
					return true;
				}
				else
				{
					var valueString = (string)target;
					if (TrimWhiteSpace)
					{
						valueString = valueString.Trim();
					}
					return !String.Equals(valueString, InitialValue, stringComparison.Value);
				}
			}
			else
			{
				if (target == null)
				{
					return false;
				}
				else
				{
					var valueString = (string)target;
					if (TrimWhiteSpace)
					{
						valueString = valueString.Trim();
					}
					return (valueString.Length > 0);
				}
			}
		}

    }
}